<?php
kan_import('UserManager.php');
kan_import('adjacency');

class ArticlesManager extends Manager {

    protected $models = array('ArticleCategory', 'Article', 'ArticleComment');
    protected $template = "articles.php";
    
    private $db = NULL;
    private $tree = NULL;

    public function __construct() {
        parent::__construct('articles', 'article_categories');
        $this->setItemClassName('Article');
        $this->setCategoryClassName('ArticleCategory');

        $this->db = $this->getDatabase();

        $this->tree = new adjacencyTree();
        $this->tree->setdbtable( $this->ArticleCategory->getTableName() );
        $this->tree->setidfield("id");
        $this->tree->setparentidfield("ParentID");
        $this->tree->setpositionfield("Position");
        $this->tree->setWhereClause("WHERE SiteID = " . SITE_ID);
        $this->tree->setDBConnectionID($this->getDatabase()->getConnection());
    }

    /**
     * Returns the internal tree handler component for the categories list
     * 
     * @return adjacencyTree
     */
    public function getAdjacencyTree() {
        return $this->tree;
    }

    /**
     * Returns and array of article categories.
     * @param string $siteid
     * @return array ArticleCategory array
     */
    public function getArticleCategories() {
		
		return $this->ArticleCategory->find( array(
			'filter' => array('SiteID' => SITE_ID),
			'order' => array('id','ParentID')
		));
    }

    /**
     * Adds and returns a new article category for the current site
     * @return ArticleCategory
     */
    public function addCategory() {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

		$category = new ArticleCategory(array(
			'SiteID' => SITE_ID,
			'ParentID' => isset($_POST['ParentID']) ? $_POST['ParentID'] : "",
			'Position' => $_POST['Position'],
			'CategoryName' => $_POST['CategoryName'],
			'CategoryAlias' => $_POST['CategoryAlias'],
			'CategoryDescription' => $_POST['CategoryDescription']
		));
		$category->save();
        

        return $category;
    }

    /**
     * Updates and returns the edited category
     * @return ArticleCategory
     */
    public function updateCategory() {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

		$category = new ArticleCategory($_POST['id']);
		$category->setData(array(
			'ParentID' => isset($_POST['ParentID']) ? $_POST['ParentID'] : "",
			'Position' => $_POST['Position'],
			'CategoryName' => $_POST['CategoryName'],
			'CategoryAlias' => $_POST['CategoryAlias'],
			'CategoryDescription' => $_POST['CategoryDescription']
		));
		$category->save();

        return $category;
    }

    /**
     * Deletes the article category with the specified ID from the database
     * 
     * @param int $category_id
     */
    public function deleteCategory($category_id) {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

		$category = new ArticleCategory($category_id);
		$category->delete();
    }

    /**
     * Returns the ArticleCategory with the specified ID or CategoryAlias for the currently
     * viewed site or a specified site if the siteid parameter is specified
     * 
     * @param mixed $id
     * @param string $siteid
     * @return ArticleCategory 
     */
    public function getCategory($id) {
        if (!isset($id)) {
            return NULL;
        }
		
		return $this->ArticleCategory->findFirst( array(
			'filter' => array(
				'OR' => array(
					'id' => $id,
					'CategoryAlias' => $id
				),
				'SiteID' => SITE_ID
			)
		));
    }

    /**
     * Return the article with the specified $id. This could either be the record ID or
     * ArticleTitleAlias. Articles returned are specified to the currently viewed site
     * 
     * @param mixed $id
     * @param string $siteid
     * @return Article 
     */
    public function getArticle($id, $siteid = -1) {
        if (!isset($id)) {
            return NULL;
        }
		
		return $this->Article->findFirst( array(
			'filter' => array(
				'SiteID' => SITE_ID,
				'OR' => array(
					'id' => $id,
					'ArticleTitleAlias' => $id
				)
			)
		));
    }

    /**
     * Returns the articles in for the currently viewed site. The start and limit parameter
     * can be used to determine how many articles are returned and can also be used to provide
     * a paging system. 
     * 
     * The options parameter enables you to change how articles are fetched and the order in why they
     * are returned, based on the Model::find parameter options
     * 
     * The published only field would cause only published articles to be returned. This true by default
     * 
     * @param int $start
     * @param int $limit
     * @param array $options
     * @param bool $publishedOnly
     * @return array 
     */
    public function getArticles($start = 0, $limit = NULL, $options = NULL, $publishedOnly = true) {

        $default = array(
            "join" => array("article_categories ac" => "ac.id = Article.categoryid AND ac.SiteID = " . SITE_ID),
            "order" => "Article.id DESC"
        );

        if ($publishedOnly) {
            $default = array(
                "join" => array("article_categories ac" => "ac.id = Article.categoryid AND ac.SiteID = " . SITE_ID),
                "filter" => array("Article.Published" => 1),
                "order" => "Article.id DESC"
            );
        }

        if ($options != NULL && is_array($options)) {
            $default = array_merge($default, $options);
        }

        return $this->getItems($start, $limit, $default);
    }

    /**
     * Returns an array of ArticleComment objects based on the supplied parameters
     */
    public function getArticleComments($siteid = -1, $start = 0, $total = NULL, $show = "all") {

        if ($siteid == -1 && defined("SITE_ID")) {
            $siteid = SITE_ID;
        }

        $db = $this->getDatabase();

        $filter = "";
        switch ($show) {
            case 'pending':
                $filter = " AND c.Approved = 0 ";
                break;
            case 'approved':
                $filter = " AND c.Approved = 1 ";
                break;
            case 'all':
            default:
                $filter = "";
        }

        $query = sprintf("SELECT c.*, a.ArticleTitle FROM article_comments c "
            . "INNER JOIN articles a ON a.id = c.ArticleID "
            . "INNER JOIN article_categories ac ON ac.id = a.CategoryID "
            . "WHERE ac.SiteID = %s {$filter} ORDER BY c.id DESC", $db->sanitizeInput($siteid, 'int'));

        if ($total != NULL) {
            $query .= sprintf(" LIMIT %s, %s", $db->sanitizeInput($start, 'int'), $db->sanitizeInput($total, 'int'));
        }

        $db->query($query);
        $comments = array();

        for ($i = 0; $i < $db->getResultCount(); $i++) {
            array_push($comments, new ArticleComment($db->getRow($i)));
        }

        return $comments;
    }

    /**
     * Returns the total number of articles in the system (Site). The show parameter determines
     * the total count based on the following options
     * - unapproved: articles that are yet to be approved
     * - approved: articles that have been approved
     * - all: all article comments
     * 
     * @param string $show
     * @return int
     */
    public function getTotalArticleCount($show = 'all') {
        $db = $this->getDatabase();

        $filter = "";
        switch ($show) {
            case 'approved':
                $filter = " AND Published = 1 ";
                break;
            case 'unapproved':
                $filter = " AND Published = 0 ";
                break;
            case 'all':
            default:
                $filter = "";
        }

        $selectSQL = sprintf("SELECT count(id) AS cnt FROM articles WHERE SiteID = %s {$filter}", $db->sanitizeInput(SITE_ID, 'int'));

        $row = $db->query($selectSQL, true)->getRow();

        return $row['cnt'];
    }

    /**
     * Returns the total number of comments in the system. The show parameter determines
     * the total count based on the following options
     * - pending: articles comment that are yet to be approved
     * - approved: articles comments that have been approved
     * - all: all article comments
     * 
     * @param string $show
     * @return int
     */
    public function getTotalCommentCount($show = 'all') {
        $db = $this->getDatabase();

        $filter = "";
        switch ($show) {
            case 'pending':
                $filter = " AND c.Approved = 0 ";
                break;
            case 'approved':
                $filter = " AND c.Approved = 1 ";
                break;
            case 'all':
            default:
                $filter = "";
        }

        $query = sprintf("SELECT count(c.id) as cnt FROM article_comments c "
            . "INNER JOIN articles a ON a.id = c.ArticleID "
            . "WHERE a.SiteID = %s {$filter}", $db->sanitizeInput(SITE_ID, 'int'));

        $row = $db->query($query, true)->getRow();
        return $row['cnt'];
    }

    /***
     * A CMS function that adds a new article to the system
     */
    public function createNewArticle() {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

        $db = $this->getDatabase();

        $insertSQL = sprintf("INSERT INTO articles (SiteID, CategoryID, ArticleTitle, ArticleTitleAlias, ArticleSummary, ArticleContent, ArticleSource, ArticleURL, ArticleGallery, AllowComments, ArticleImage, ArticleThumbnail, PostDate) "
            . "VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, now())", $db->sanitizeInput($_SESSION['siteid'], "int"), $db->sanitizeInput($_POST['CategoryID'], "int"), $db->sanitizeInput($_POST['ArticleTitle'], "text"), $db->sanitizeInput($_POST['ArticleTitleAlias'], "text"), $db->sanitizeInput($_POST['ArticleSummary'], "text"), $db->sanitizeInput($_POST['ArticleContent'], "text"), $db->sanitizeInput($_POST['ArticleSource'], "text"), $db->sanitizeInput($_POST['ArticleURL'], "text"), $db->sanitizeInput($_POST['ArticleGallery'], "text"), $db->sanitizeInput($_POST['AllowComments'], "int"), $db->sanitizeInput($_POST['ArticleImage'], "text"), $db->sanitizeInput($_POST['ArticleThumbnail'], "text"));

        $db->query($insertSQL, true);
    }

    /**
     * This is a CMS function that updates or saves the information about an article to the database
     * 
     */
    public function updateArticle() {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

        $db = $this->getDatabase();

        $updateSQL = sprintf("UPDATE articles SET SiteID = %s, CategoryID = %s, ArticleTitle = %s, ArticleTitleAlias = %s, ArticleSummary = %s, ArticleContent = %s, ArticleSource = %s, ArticleURL = %s, ArticleGallery = %s, AllowComments = %s, ArticleImage = %s, ArticleThumbnail = %s WHERE id = %s ", $db->sanitizeInput($_SESSION['siteid'], 'int'), $db->sanitizeInput($_POST['CategoryID'], "int"), $db->sanitizeInput($_POST['ArticleTitle'], "text"), $db->sanitizeInput($_POST['ArticleTitleAlias'], "text"), $db->sanitizeInput($_POST['ArticleSummary'], "text"), $db->sanitizeInput($_POST['ArticleContent'], "text"), $db->sanitizeInput($_POST['ArticleSource'], "text"), $db->sanitizeInput($_POST['ArticleURL'], "text"), $db->sanitizeInput($_POST['ArticleGallery'], "text"), $db->sanitizeInput($_POST['AllowComments'], "int"), $db->sanitizeInput($_POST['ArticleImage'], "text"), $db->sanitizeInput($_POST['ArticleThumbnail'], "text"), $db->sanitizeInput($_POST['id'], 'int'));

        $db->query($updateSQL, true);
    }

    /**
     * Publishes/Unpublishes an article in the system
     * 
     * @param int $id
     * @param bool $publish
     */
    public function publishArticle($id, $publish = true) {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

        $db = $this->getDatabase();

        $updateSQL = sprintf("UPDATE articles SET Published = %s WHERE id = %s", $db->sanitizeInput($publish ? 1 : 0, 'int'), $db->sanitizeInput($id, 'int'));

        echo $updateSQL;

        $db->query($updateSQL, true);
    }

    /**
     * Deletes the articles with the specified ID or IDs from the database
     *
     * @param array $ids the ID or IDs to delete, can be an array or an int
     */
    public function deleteArticles($ids) {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

        if (!is_array($ids) && !is_int($ids)) {
            die("Invalid Parameter Passed In " . __FILE__ . " On Line " . __LINE__ . " To Method " . __METHOD__);
        }
        
        $this->Article->deleteAll( array('id IN' => $ids));
    }

    /**
     * Moves the articles with the specified IDs to a new category
     * 
     * @param array $ids an array of IDs to move
     * @param int $category_id new category ID
     */
    public function moveArticles($ids, $category_id) {
        if (!defined("IN_CMS") || !IN_CMS) {
            return;
        }

        if (!is_array($ids) && !is_int($ids)) {
            die("Invalid Parameter Passed In " . __FILE__ . " On Line " . __LINE__ . " To Method " . __METHOD__);
        }

        $this->Article->updateAll(array('CategoryID' => $category_id), array('id IN' => $ids));
    }
    

    /**
     * Adds an article comment to the system, and fires a notification email to the site
     * Admin about the new comment
     *
     * @global Site $site
     * @param int $article_id
     * @param array $comment_data
     * @return ArticleComment 
     */
    public function addArticleComment($article_id, $comment_data) {
        global $site;

        if (!is_array($comment_data)) {
            trigger_error("Comment Data Parameter Should Be An Array");
            return NULL;
        }
        
        if( intval($article_id) <= 0 ) {
            trigger_error("Invalid Article ID Specified");
            return NULL;
        }

        $article = $this->getArticle($article_id);
        $comment = new ArticleComment($comment_data);
        $comment->setData('ArticleID', $article_id);
        $comment->save();

        if ($comment->getId() != "") {
            $cms_url = kan_fix_url("../cms/", true); // add true param so HOST information is included in the URL

            $message = "New Comment On The Article \"" . $article->getTitle() . "\" <br />";
            $message .= "Author : " . $comment->getReaderName() . "<br />"
                . "Email: " . $comment->getReaderEmail() . "<br />"
                . "Website: " . $comment->getReaderWebsite() . "<br />"
                . "Comment: <br />" . $comment->getMessage() . "<br /><br />";

            $message .= "You can see all comments here: <a href='" . SITE_HOST . $article->getURL() . "#comments'>" . SITE_HOST . $article->getURL() . "#comments</a> <br /><br />";

            $message .= "You can login to the Content Manager Interface of your site to moderate this comment. <br />"
                . "<a href='$cms_url'>Click here to login to the CMS</a>";

            $um = new UserManager();
            $superUser = $um->getUserRole('super');

            $fm = new FeedbackManager();
            $fm->sendMessage(array(
                'to' => $site->getSiteEmail() ? $site->getSiteEmail() : $superUser->getEmail(),
                //'from' => $comment->getReaderEmail(),
                'senderName' => $comment->getReaderName(),
                'subject' => "Comment On " . $article->getTitle(),
                'message' => $message
            ));
        }

        return $comment;
    }

    /**
     * Approves or Disapproves an article comment
     * 
     * @param mixed $article_ids int or array
     * @param bool $approve 
     */
    public function approveComments($article_ids, $approve = true) {
        if (!is_array($article_ids) && !is_int($article_ids)) {
            trigger_error("Supplied parameter 'article_ids' should be either an int or an array");
            return;
        }
        
        $this->ArticleComment->updateAll(array('Approved' => $approve ? 1 : 0), array('id IN' => $article_ids));
    }

    /**
     * Deletes the comments with the specified ID or ids from the system
     * 
     * @param mixed $article_ids int or array of ids
     */
    public function deleteComments($article_ids) {
        if (!is_array($article_ids) && !is_int($article_ids)) {
            trigger_error("Supplied parameter 'article_ids' should be either an int or an array");
            return;
        }
        
        $this->ArticleComment->deleteAll(array('id IN' => $article_ids));
    }

    /**
     * Generates an HTML UL list of Linked ArticleCategory names
     * 
     * @param string $class
     * @param int $depth
     * @param bool $includeHome
     * @param int $startDepth 
     */
    public function getCategoriesAsHTMLList($class = 'nav', $depth = 10, $startDepth = 1) {

        $nodes = $this->getAdjacencyTree()->getFullNodes();

        echo "<ul class='$class'>";
        $this->printCategoryList($nodes, $depth, $startDepth);
        echo "</ul>";
    }

    /**
     * Used by the getCategoriesAsHTMLList function to generate the list
     * 
     * @param array $cat_data
     * @param int $depth
     * @param int $startDepth 
     */
    private function printCategoryList($cat_data, $depth, $startDepth) {
        $currentDepth = $startDepth;
        $thisDepth = $startDepth;

        foreach ($cat_data as $data) {
            $category = new ArticleCategory($data);

            ?>

            <li id="cat-li-<?php echo $category->getId(); ?>">
                <a id="cat-<?php echo $category->getId(); ?>" data-id="<?php echo $category->getId(); ?>" href='<?php echo $category->getURL(); ?>'><?php echo $category->getCategoryName(); ?></a><?php
            if (isset($data['children']) && $currentDepth < $depth) {
                echo "<ul>";
                $this->printCategoryList($data['children'], $depth, ++$currentDepth);
                echo "</ul>";
            }
            ?>

            </li><?php
            $currentDepth = $thisDepth;
        }
    }

    /**
     * Returns the URL to the General system Articles Feed
     * 
     * @return string
     */
    public function getArticlesFeedURL() {
        if (SEF_URLS) {
            return kan_fix_url("../" . SITE_TAG . "/feed/articles/");
        }

        return kan_fix_url("../pages/feed.php?siteid=" . SITE_TAG . "&content=articles");
    }
	
	public function findArticlesBy($params) {
		
		$conditions = array();
		
		if( $params['month'] ) {
			$conditions["MONTHNAME(Article.PostDate)"] = $params['month'];	
		}
		
		if( $params['year'] ) {
			$conditions['YEAR(Article.PostDate)'] = $params['year'];	
		}
	}

    /**
     * Overrides and implements the rendering for the articles view
     */
    public function render() {
        global $site;
		
        $category = NULL;
        $article = NULL;
        
        if (isset($_GET['category'])) {
            $category = $this->getCategory(kan_get_parameter('category'));
        }

        if (isset($_GET['id'])) {
            $article = $this->getArticle(kan_get_parameter('id'));
			
			if( $article ) {
				$site->setData('SiteDescription', strip_tags($article->getSummary()) );
			}
            
        } else if (isset($_GET['url'])) {
            // the url parameters
            $parts = explode("/", kan_get_parameter('url'));

            // if the url parameters contains more than two parameters then the url is
            // valid and the article can be loaded. e.g. news/article-title
            if (count($parts) >= 1 && !empty($parts[0])) {
                $category = $this->getCategory(kan_clean_input($parts[0]));
            }
			
			if (count($parts) >= 1 && !empty($parts[0]) && strtolower($parts[0]) == "search") {
				
			}

            if (count($parts) >= 2 && !empty($parts[1])) {
                $article = $this->getArticle(kan_clean_input($parts[1]));
				
				if( $article ) {
					$site->setData('SiteDescription', strip_tags($article->getSummary()) );
				}
            }
        }
        
        $this->set("article", $article);
        $this->set("category", $category);
        
        parent::render();
    }

    /* public function getArchiveList() {
      $db = $this->getDatabase();
      $sql = "SELECT  YEAR(DatePosted) AS 'Year', MONTH(DatePosted) AS 'Month', MONTHNAME(DatePosted) AS 'MonthName', COUNT(id) AS Total
      FROM tbcmessage
      GROUP BY YEAR(DatePosted), MONTH(DatePosted)
      ORDER BY YEAR(DatePosted), MONTH(DatePosted)";

      $db->query($sql);

      echo "<ul>";
      $lastYear = "";
      for ($i = 0; $i < $db->getResultCount(); $i++) {
      $data = $db->getRow($i);
      if ($lastYear != $data['Year']) {
      $lastYear = $data['Year'];
      echo "<h4>" . $data['Year'] . "</h4>";
      }

      $url = kan_fix_url("../pages/audio.php?siteid=" . SITE_TAG . "&view=archive&y=" . $data['Year'] . "&m=" . $data['Month']);
      echo "<li><a href='" . $url . "'>" . $data['MonthName'] . " (" . $data['Total'] . ") </a></li>";
      }

      echo "</ul>";
      }

      public function getArchivedMessages($year, $month) {
      $db = $this->getDatabase();

      $sql = sprintf("SELECT * FROM tbcmessage WHERE Year(DatePosted) = %s AND Month(DatePosted) = %s", $db->sanitizeInput($year, 'int'), $db->sanitizeInput($month, 'int'));

      $db->query($sql, true);
      $audioFiles = array();

      for ($i = 0; $i < $db->getResultCount(); $i++) {
      $audioFiles[] = new Audio($db->getRow($i));
      }

      return $audioFiles;
      } */
}
?>